package dbms.absyn;

import dbms.symbol.Symbol;

public class Condition {
	public int pos;
	public boolean flag;
	//usual name="hello"
	public Symbol op;
	public Attribute attr;
	
	//attr1 op attr2
	public Attribute attr1;
	public Attribute attr2;
	
	public Value value;
	//between .. and ..
	public Value value_left;
	public Value value_right;
	// IN ...
	public ValueList value_list;
	
	//NOT 
	public Condition condition;
	
	//IN SelectExp
	public SelectExp exp;
	
	public int type = 0;
	
	//ID op value
	public Condition (int p, Attribute symbol, Symbol o, Value v) {
		pos = p;
		flag = true;
		attr = symbol;
		op = o;
		value = v;
		type = 1;
	}
	
	//NOT condition
	public Condition (String string, int pos2, Condition c) {
		pos = pos2;
		flag = false;
		condition = c;
		type = 2;
	}
	
	//ID BETWEEN valueA AND valueB
	public Condition (int p, Attribute s, Value va, Value vb) {
		pos = p;
		flag = true;
		attr = s;
		value_left = va;
		value_right = vb;
		type = 3;
	}
	
	//ID IN ValueList
	public Condition (int p, Attribute s, ValueList vl) {
		pos = p;
		flag = true;
		attr = s;
		value_list = vl;
		type = 4;
	}
	
	//ID IN SelectExp
	public Condition(int attrleft, Attribute sym, SelectExp se) {
		pos = attrleft;
		attr = sym;
		exp = se;
		type = 5;
	}

	public Condition(int p, Attribute attr1, Symbol o, Attribute attr2) {
		pos = p;
		this.attr1 = attr1;
		op = o;
		this.attr2 = attr2;
		type = 6;
	}

	public boolean satisfyInt(int i) {
		switch(type) {
		case 1://ID op value
			if (op.name.equals("EQ")) return (i == value.number);
			if (op.name.equals("GT")) return (i > value.number);
			if (op.name.equals("GTE")) return (i >= value.number);
			if (op.name.equals("LT")) return (i < value.number);
			if (op.name.equals("LTE")) return (i <= value.number);
			if (op.name.equals("NEQ")) return (i != value.number);
			break;
		case 2://NOT condition
			if (condition.satisfy(i)) return false;
			else return true;
		case 3://ID BETWEEN valueA AND valueB
			if ((i >= value_left.number) && (i <= value_right.number)) return true;
			else return false;
		case 4://ID IN ValueList
			ValueList vl = value_list;
			while (vl != null) {
				if (i == vl.value.number) return true;
				else vl = vl.next;
			}
			return false;
		}
		//Unexpected Case
		return false;
	}
	
	public boolean satisfyString(String s) {
		switch(type) {
		case 1://ID op value
			if (op.name.equals("EQ")) return (s.equals(value.str));
			if (op.name.equals("GT")) return (s.compareTo(value.str) > 0);
			if (op.name.equals("GTE")) return (s.compareTo(value.str) >= 0);
			if (op.name.equals("LT")) return (s.compareTo(value.str) < 0);
			if (op.name.equals("LTE")) return (s.compareTo(value.str) <= 0);
			if (op.name.equals("NEQ")) return (s.equals(value.str));
			break;
		case 2://NOT condition
			return (!condition.satisfy(s));
		case 3://ID BETWEEN valueA AND valueB
			if ((s.compareTo(value_left.str) >= 0) && (s.compareTo(value_right.str) <= 0)) return true;
			else return false;
		case 4://ID IN ValueList
			ValueList vl = value_list;
			while (vl != null) {
				if (s.equals(vl.value.str)) return true;
				else vl = vl.next;
			}
			return false;
		}
		//Unexpected Case
		return false;
	}
	
	public boolean satisfyIntAttr(int i, int j) {
		//Unexpected Case
		if (type != 6) return false;
		if (op.name.equals("EQ")) return (i == j);
		if (op.name.equals("GT")) return (i > j);
		if (op.name.equals("GTE")) return (i >= j);
		if (op.name.equals("LT")) return (i < j);
		if (op.name.equals("LTE")) return (i <= j);
		if (op.name.equals("NEQ")) return (i != j);
		//Unexpected Case
		return false;
	}
	
	public boolean satisfyStrAttr(String s, String t) {
		//Unexpected Case
		if (type != 6) return false;
		if (op.name.equals("EQ")) return (s.equals(t));
		if (op.name.equals("GT")) return (s.compareTo(t) > 0);
		if (op.name.equals("GTE")) return (s.compareTo(t) >= 0);
		if (op.name.equals("LT")) return (s.compareTo(t) < 0);
		if (op.name.equals("LTE")) return (s.compareTo(t) <= 0);
		if (op.name.equals("NEQ")) return (!s.equals(t));
		//Unexpected Case
		return false;
	}
	
	public boolean satisfy(Object o) {
		if (o instanceof Integer) return satisfyInt((Integer)o);
		if (o instanceof String) return satisfyString((String)o);
		//Unexpected Case
		return false;
	}

	public boolean satisfyAttr(Object va, Object vb) {
		if ((va instanceof Integer) && (vb instanceof Integer)) return satisfyIntAttr((Integer) va, (Integer) vb);
		if ((va instanceof String) && (vb instanceof String)) return satisfyStrAttr((String) va, (String) vb);
		//Unexpected Case
		return false;
	}
}
